package cn.cqautotest.cqviehelper.views;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ListView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;
import androidx.core.widget.ListViewCompat;

import cn.cqautotest.cqviehelper.R;

/**
 * @author A lonely cat
 * <p>
 * description：藏宝视图，由于像藏宝藏一样，平常是被埋藏起来的，所以叫做藏宝视图。
 */
public class TreasureView extends FrameLayout {

    private static final String TAG = TreasureView.class.getSimpleName();
    //默认隐藏的View
    private View mTreasure;
    //需要滑动的View
    private View mTarget;
    //按下时的Y轴坐标
    private float mPressY;
    //可以滑动的最大高度
    private float mMaxHeight;
    // 滑动多少距离才算是滑动，否则有时候是点击也会误触发滑动
    private int minDist;
    private float mOffsetY;
    //是否启用
    private boolean mEnabled = true;
    public static final float DEFAULT_MARGIN_TOP_HEIGHT = 0;
    private float mMarginTopHeight = DEFAULT_MARGIN_TOP_HEIGHT;
    private float mPressX;

    public TreasureView(@NonNull Context context) {
        this(context, null);
    }

    public TreasureView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TreasureView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initView();
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TreasureView);
        mEnabled = typedArray.getBoolean(R.styleable.TreasureView_enabled, true);
        mMarginTopHeight = typedArray.getDimension(R.styleable.TreasureView_margin_top_height, DEFAULT_MARGIN_TOP_HEIGHT);
        typedArray.recycle();
    }

    private void initView() {
        InflateLayout();
        //Log.d(TAG, "TreasureView: ======> The maximum distance the user can slide is " + mMaxHeight);
        //在我们认为用户正在滚动之前，触摸就可以移动以像素为单位的距离。
        minDist = ViewConfiguration.get(getContext()).getScaledTouchSlop();
    }

    public TreasureView enabled(boolean enabled) {
        mEnabled = enabled;
        return this;
    }

    /**
     * 加载布局
     */
    private void InflateLayout() {
        if (getTreasureLayoutResId() != 0) {
            LayoutInflater.from(getContext()).inflate(getTreasureLayoutResId(), this);
        }
        if (getTreasureView() != null) {
            mTreasure = getTreasureView();
            addView(mTreasure);
            setUpEvent();
        }
        if (getTargetLayoutResId() != 0) {
            LayoutInflater.from(getContext()).inflate(getTargetLayoutResId(), this);
        }
        if (getTargetView() != null) {
            mTarget = getTargetView();
            addView(mTarget);
        }
    }

    /**
     * 获取到 mTreasure 的布局资源Id
     *
     * @return TreasureLayoutResId
     */
    protected int getTreasureLayoutResId() {
        //return R.layout.include_simple_text;
        return 0;
    }

    public View getTreasureView() {
        return mTreasure;
    }

    public TreasureView setTreasureView(View treasure) {
        mTreasure = treasure;
        mTreasure.measure(0, 0);
        mMaxHeight = mTreasure.getMeasuredHeight();
        setUpEvent();
        return this;
    }

    /**
     * 获取到 mTarget 的布局资源Id
     *
     * @return TargetLayoutResId
     */
    protected int getTargetLayoutResId() {
        //return R.layout.include_mark_layout;
        return 0;
    }

    public View getTargetView() {
        return mTarget;
    }

    public TreasureView setTargetView(View target) {
        mTarget = target;
        invalidate();
        return this;
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
        if (getChildCount() > 2) {
            throw new IllegalArgumentException("Cannot add the third child to the ViewGroup !");
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //在按下的时候获取到y轴的坐标
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            mPressX = ev.getX();
            mPressY = ev.getY();
        }
        if (ev.getAction() == MotionEvent.ACTION_MOVE) {
            //如果是启用状态且比规定的阈值大，则判定为滑动，否则进行默认处理
            if (mEnabled && Math.abs(ev.getX() - mPressY) > minDist) {
                //如果当前下拉偏移量大于最小偏移量，并且子控件不能向上滚动，则将事件交给自己处理
                if (ev.getY() - mPressY >= minDist && !canChildScrollUp()) return true;
                //如果当前上拉偏移量大于最小偏移量，并且子控件不能向下滚动，则将事件交给自己处理
                if (mPressY - ev.getY() >= minDist && !canChildScrollDown()) return true;
            }
        }
        return super.onInterceptTouchEvent(ev);
    }

    /**
     * 此布局的子视图是否有可能向上滚动。如果子视图是自定义视图，则重写此方法。
     *
     * @return Whether it is possible for the child view of this layout to
     * scroll up. Override this if the child view is a custom view.
     */
    public boolean canChildScrollUp() {
        return mTarget instanceof ListView ? ListViewCompat.canScrollList((ListView) mTarget, -1)
                : mTarget.canScrollVertically(-1);
    }

    public boolean canChildScrollDown() {
        return mTarget instanceof ListView ? ListViewCompat.canScrollList((ListView) mTarget, 1)
                : mTarget.canScrollVertically(1);
    }

    private UIStates currentState = UIStates.CLOSE;

    private enum UIStates {
        CLOSE, OPEN
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //再次获取当前按下的y轴坐标
                mPressY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                //获取到在y轴移动的偏移量
                mOffsetY = event.getY() - mPressY;
                //只有在向下的偏移量大于0时，才能继续下拉
                if (mOffsetY > 0) {
                    //如果Y轴的偏移量超过可下拉的最大距离，则Y轴的偏移量就等于可下拉最大距离
                    if (mOffsetY > minDist * 3) mOffsetY = mMaxHeight;
                    //如果向下的偏移距离等于可下拉的最大距离，则我们认为是打开状态
                    if (mOffsetY == mMaxHeight) currentState = UIStates.OPEN;
                } else {
                    //顶到最上面，松手时自动恢复默认状态
                    mOffsetY = mMarginTopHeight;
                    currentState = UIStates.CLOSE;
                }
                mTreasure.setVisibility(mOffsetY < 0 ? GONE : VISIBLE);
                verticalScroll(mOffsetY);
                //向上滑动时置为默认状态
                //if (mOffsetY < 0 && mOffsetY < -mMaxHeight) currentState = UIStates.CLOSE;
                //显得滑动没那么生硬
                if (mOffsetY < -minDist) currentState = UIStates.CLOSE;
                break;
            case MotionEvent.ACTION_UP:
                callDifferentMethod();
                break;
        }
        return true;
    }

    /**
     * 根据当前状态调用不同的方法
     */
    private void callDifferentMethod() {
        switch (currentState) {
            case OPEN:
                setOpen();
                break;
            case CLOSE:
                setClose();
                break;
            default:
                break;
        }
    }

    /**
     * 用于滚动目标View的方法
     *
     * @param offsetY 目标View在Y轴上的偏移量
     */
    private void verticalScroll(float offsetY) {
        mTarget.setTranslationY(offsetY);
    }

    /**
     * 设置为打开状态
     */
    public void setOpen() {
        if (currentState != UIStates.OPEN) currentState = UIStates.OPEN;
        verticalScroll(mMaxHeight);
        if (mOnStateChangedListener != null) mOnStateChangedListener.onOpen();
    }

    /**
     * 设置为关闭状态
     */
    public void setClose() {
        mTreasure.setVisibility(VISIBLE);
        if (currentState != UIStates.CLOSE) currentState = UIStates.CLOSE;
        verticalScroll(0f + mMarginTopHeight);
        if (mOnStateChangedListener != null) mOnStateChangedListener.onClose();
    }

    /**
     * 设置状态改变的监听器
     *
     * @param onStateChangedListener
     */
    public void setOnStateChangedListener(OnStateChangedListener onStateChangedListener) {
        mOnStateChangedListener = onStateChangedListener;
    }

    public static abstract class OnStateChanged implements OnStateChangedListener {
        @Override
        public void onTreasureClick(View view) {

        }

        @Override
        public void onOpen() {

        }

        @Override
        public void onClose() {

        }
    }

    private OnStateChangedListener mOnStateChangedListener = null;

    /**
     * 给外界提供状态改变监听的接口
     */
    public interface OnStateChangedListener {

        void onTreasureClick(View view);

        void onOpen();

        void onClose();
    }

    /**
     * 在测量时获取到可下拉的最大高度
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //此处不能直接通过 mHideView.getHeight() 获得该控件的高度
        mMaxHeight = mTreasure.getMeasuredHeight();
        if (mTarget == null) ensureTarget();
    }

    /**
     * 在布局载入完毕后找到 mTreasure 和 mTarget
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mTreasure = getChildAt(0);
        setUpEvent();
        //防止出现 CardView 浮在布局上方的情况
        if (mTreasure instanceof CardView) mTreasure.setTranslationZ(-999);
        if (mTarget == null) ensureTarget();
    }

    private void setUpEvent() {
        mTreasure.setOnClickListener(v -> mOnStateChangedListener.onTreasureClick(v));
    }

    /**
     * 找到子控件（需要滑动的View）
     */
    private void ensureTarget() {
        // Don't bother getting the parent height if the parent hasn't been laid
        // out yet.
        if (mTarget == null) {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (!mTreasure.equals(child)) {
                    mTarget = child;
                    verticalScroll(mMarginTopHeight);
                    //如果目标View没有设置背景颜色，则默认设置为白色
                    if (mTarget.getBackground() == null) mTarget.setBackgroundColor(Color.WHITE);
                    break;
                }
            }
        }
        if (mTarget == null) {
            throw new NullPointerException("mTarget is null，Please add mTarget View to ViewGroup ！");
        }
        if (getChildCount() > 2) {
            throw new IllegalArgumentException("Parent have up to two child !");
        }
    }
}
